// Copyright (c) 2024 Go-Frame-Lite
// Go-Frame-Lite is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//         http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

// Package logger provides structured logging functionality using zap logger.
package logger

import (
	"context"
	"os"
	"path/filepath"
	"sync"

	"go-frame-lite/pkg/configtypes"
	"go-frame-lite/pkg/trace"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// globalLogger 全局日志记录器
var (
	globalLogger *zap.Logger
	loggerMutex  sync.RWMutex
	loggerOnce   sync.Once
)

// NewLogger 创建新的日志记录器
func NewLogger(config configtypes.LogConfig) (*zap.Logger, error) {
	// 确保日志目录存在
	if err := os.MkdirAll(filepath.Dir(config.FilePath), 0o750); err != nil {
		return nil, err
	}

	// 设置日志级别
	level := zap.InfoLevel
	switch config.Level {
	case "debug":
		level = zap.DebugLevel
	case "warn":
		level = zap.WarnLevel
	case "error":
		level = zap.ErrorLevel
	case "fatal":
		level = zap.FatalLevel
	case "panic":
		level = zap.PanicLevel
	}

	// 配置编码器
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	// 创建文件写入器
	file, err := os.OpenFile(config.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600)
	if err != nil {
		return nil, err
	}
	fileWriter := zapcore.AddSync(file)

	// 创建控制台写入器
	consoleWriter := zapcore.AddSync(os.Stdout)

	// 创建核心
	cores := []zapcore.Core{}

	// 文件输出（JSON格式）
	cores = append(cores, zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig),
		fileWriter,
		level,
	))

	// 控制台输出（控制台格式）
	if config.Console {
		consoleEncoderConfig := encoderConfig
		consoleEncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
		cores = append(cores, zapcore.NewCore(
			zapcore.NewConsoleEncoder(consoleEncoderConfig),
			consoleWriter,
			level,
		))
	}

	// 创建日志记录器
	logger := zap.New(
		zapcore.NewTee(cores...),
		zap.AddCaller(),
		zap.AddCallerSkip(1),
		zap.AddStacktrace(zapcore.ErrorLevel),
	)

	return logger, nil
}

// setGlobalLogger 内部设置全局日志记录器
func setGlobalLogger(logger *zap.Logger) {
	loggerMutex.Lock()
	defer loggerMutex.Unlock()
	globalLogger = logger
}

// getGlobalLogger 内部获取全局日志记录器
func getGlobalLogger() *zap.Logger {
	loggerMutex.RLock()
	defer loggerMutex.RUnlock()
	return globalLogger
}

// ensureGlobalLogger 确保全局日志记录器已初始化
func ensureGlobalLogger() {
	if getGlobalLogger() == nil {
		// 自动使用开发环境配置作为默认值
		config := configtypes.LogConfig{
			Level:    "info",
			FilePath: "logs/app.log",
			Console:  true,
		}
		if logger, err := NewLogger(config); err == nil {
			setGlobalLogger(logger)
		}
	}
}

// Init 初始化全局日志记录器（用户可选的显式初始化）
func Init(config configtypes.LogConfig) error {
	var initErr error
	loggerOnce.Do(func() {
		logger, err := NewLogger(config)
		if err != nil {
			initErr = err
			return
		}
		setGlobalLogger(logger)
	})
	return initErr
}

// InitDevelopment 初始化开发环境全局日志记录器
func InitDevelopment() error {
	config := configtypes.LogConfig{
		Level:    "debug",
		FilePath: "logs/development.log",
		Console:  true,
	}
	return Init(config)
}

// InitProduction 初始化生产环境全局日志记录器
func InitProduction() error {
	config := configtypes.LogConfig{
		Level:    "info",
		FilePath: "logs/production.log",
		Console:  false,
	}
	return Init(config)
}

// 全局日志快捷方法（所有方法第一个参数都是ctx）

// Debug 调试日志
func Debug(ctx context.Context, msg string, fields ...zap.Field) {
	ensureGlobalLogger()
	if logger := getGlobalLogger(); logger != nil {
		traceID := trace.GetTraceID(ctx)
		if traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}
		logger.Debug(msg, fields...)
	}
}

// Info 信息日志
func Info(ctx context.Context, msg string, fields ...zap.Field) {
	ensureGlobalLogger()
	if logger := getGlobalLogger(); logger != nil {
		traceID := trace.GetTraceID(ctx)
		if traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}
		logger.Info(msg, fields...)
	}
}

// Warn 警告日志
func Warn(ctx context.Context, msg string, fields ...zap.Field) {
	ensureGlobalLogger()
	if logger := getGlobalLogger(); logger != nil {
		traceID := trace.GetTraceID(ctx)
		if traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}
		logger.Warn(msg, fields...)
	}
}

// Error 错误日志
func Error(ctx context.Context, msg string, fields ...zap.Field) {
	ensureGlobalLogger()
	if logger := getGlobalLogger(); logger != nil {
		traceID := trace.GetTraceID(ctx)
		if traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}
		logger.Error(msg, fields...)
	}
}

// Fatal 致命错误日志
func Fatal(ctx context.Context, msg string, fields ...zap.Field) {
	ensureGlobalLogger()
	if logger := getGlobalLogger(); logger != nil {
		traceID := trace.GetTraceID(ctx)
		if traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}
		logger.Fatal(msg, fields...)
	}
}

// Sync 同步全局日志记录器
func Sync() error {
	if logger := getGlobalLogger(); logger != nil {
		return logger.Sync()
	}
	return nil
}

// NewDevelopmentLogger 创建开发环境日志记录器
func NewDevelopmentLogger() (*zap.Logger, error) {
	config := configtypes.LogConfig{
		Level:    "debug",
		FilePath: "logs/development.log",
		Console:  true,
	}
	return NewLogger(config)
}

// NewProductionLogger 创建生产环境日志记录器
func NewProductionLogger() (*zap.Logger, error) {
	config := configtypes.LogConfig{
		Level:    "info",
		FilePath: "logs/production.log",
		Console:  false,
	}
	return NewLogger(config)
}
